package com.laolei.core.logging;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import com.laolei.core.logging.RunTimeLog.TimeScale;
import com.laolei.core.utils.JSONUtils;
import com.laolei.core.utils.ListUtils;
import com.laolei.core.utils.MapUtils;

@Component
@EnableConfigurationProperties({ TimeScale.class })
public class RunTimeLog {

	private final static Logger LOGGER = LoggerFactory.getLogger("laolei.time.log");

	private static final ThreadLocal<Long> beginTime = new ThreadLocal<Long>() {
		protected Long initialValue() {
			return System.currentTimeMillis();
		};
	};

	private static Map<Level, Integer> timeScale = MapUtils.<Level, Integer>n().a(Level.OFF, 1000).a(Level.TRACE, 10).a(Level.DEBUG, 100).a(Level.INFO, 200).a(Level.WARN, 2000).a(Level.ERROR, 8000).to();
	private static List<Entry<Level, Integer>> timeScaleList;
	private static int offtime;

	private static void init(Map<Level, Integer> map) {
		timeScale = MapUtils.n(map).filter((k, v) -> v != null).to();
		Integer offtime_ = timeScale.remove(Level.OFF);
		offtime = offtime_ == null ? -1 : offtime_;
		timeScaleList = ListUtils.n(timeScale.entrySet()).filter(t -> t.getValue() != null).order(t -> t.getValue()).to();
	}

	public static final void clear() {
		beginTime.remove();
	}

	public static final void bedin() {
		beginTime.set(System.currentTimeMillis());
	}

	private static final long getRuntime() {
		long bedin = beginTime.get();
		long end = System.currentTimeMillis();
		beginTime.set(end);
		return end - bedin;
	}

	public static final void log(String f, Object... args) {
		log(getRuntime(), f, args);
	}

	public static final void log(long runtime, String f, Object... args) {
		if (runtime == 0 || f == null || offtime > runtime || timeScaleList.isEmpty()) {
			return;
		}
		Entry<Level, Integer> suitmin = null;
		for (Entry<Level, Integer> entry : timeScaleList) {
			if (entry.getValue() > runtime)
				break;
			suitmin = entry;
		}
		StringBuffer format = new StringBuffer("执行时间:").append(runtime).append("毫秒   ").append(f);
		output(suitmin, format.toString(), args);
	}

	private static void output(Entry<Level, Integer> suitmin, String f, Object... args) {
		if (suitmin == null) {
			LOGGER.debug(f, args);
		} else {
			switch (suitmin.getKey()) {
			case TRACE:
				LOGGER.trace(f, args);
				break;
			case DEBUG:
				LOGGER.debug(f, args);
				break;
			case INFO:
				LOGGER.info(f, args);
				break;
			case WARN:
				LOGGER.warn(f, args);
				break;
			case ERROR:
				LOGGER.error(f, args);
				break;
			default:
				LOGGER.info(f, args);
				break;
			}
		}
	}

	static {
		init(timeScale);
	}

	@ConfigurationProperties("logging")
	public class TimeScale implements InitializingBean {

		public Map<Level, Integer> getTimeScale() {
			return timeScale;
		}

		public void setTimeScale(Map<Level, Integer> timeScale) {
			RunTimeLog.timeScale = timeScale;
		}

		@Override
		public void afterPropertiesSet() throws Exception {
			init(timeScale);
			LOGGER.info("api调用日志输出时间参数配置信息{} 日志最少输出的时间 {}", JSONUtils.toJSONString(timeScaleList), offtime);
		}
	}


}
